
import { computed, reactive } from 'vue'
// import type { InjectionKey } from 'vue'
import type {
  IState,
  IStateCreateOption,
  IStateKey,
  IAnyObject
} from '../types/type'

import BaseArray from './base-array'
import BaseObject from './base-object'

// import { deepClone } from '../main'

// 日志
import {
  // stateLog, // 记录容器
  writeLog // 添加一条记录
} from '../base/_log'

/**
 * 传入参数，创建有getter、actions 的状态，reactive
 * @param id 状态的标志
 * @param info StateCreateOption state、getter、action、options
 * * state：状态：对象、数组，或者函数
 * * getters?：变成 computed 的对象集合
 * * actions?: 变成 action 的对象集合
 * * options?: 选项
 * * * isLocal —— true：局部状态；false：全局状态（默认属性）；
 * * * isLog ——  true：做记录；false：不用做记录（默认属性）；
 */
export default function optionState<T extends IAnyObject>(
    id: IStateKey,
    info: IStateCreateOption
  ): T & IState {
  
  // 判断 state 是 object 还是 array，继承不同的基类
  let tmp = null
  let basec: any = null
  // 根据 options 判断，是否需要做日志
  const isLog = !!info.options?.isLog

  const _state = (typeof info.state === 'function') ? info.state(): info.state
  if (Array.isArray(_state)) {
    // 数组，定义子类，在子类上面加 getter 和 action
    class arrayClass extends BaseArray<T> {
      constructor(_info: any) {
        super(_info, id) // 调用父类的constructor()
      }
    }
    basec = arrayClass

  } else {
    // 对象，定义子类，在子类上面加 getter 和 action
    class objClass extends BaseObject<T> {
      constructor(_info: any) {
        super(_info, id, isLog) // 调用父类的constructor()
      }
    }
    basec = objClass
  }

  // 创建实例
  tmp = new basec(info.state)
  // 套上 reactive 
  const ret = reactive(tmp)
 
  // 挂载 getters，变成 computed
  if (typeof info.getters === 'object') {
    Object.keys(info.getters).forEach(key => {
      // 在子类的原型上面挂载 computed
      basec.prototype[key] = computed(() => {
        const re = (info.getters as IAnyObject)[key].call(ret, ret)
        return re
      })
    })
  }

  // 挂载 actions
  if (typeof info.actions === 'object') {
    Object.keys(info.actions).forEach(key => {
      // 在子类的原型上面挂载 action
      basec.prototype[key] = async function (...arg: Array<any>) {
        writeLog(ret as IAnyObject, {}, `action-${key}`, 3, async () => {
          const fun = (info.actions as IAnyObject)[key]
          if (fun.toString().match(/^\(.*\) => \{/)) {
            // 箭头函数
            await (info.actions as IAnyObject)[key].call(ret, ret, ...arg)
          } else {
            // 普通函数
            await (info.actions as IAnyObject)[key].call(ret, ...arg)
          }
        })
      }
    })
  }
  
  return ret as T & IState
}